package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.utils.JsonUtils;
import com.leyou.exception.LyException;
import com.leyou.item.dto.*;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu>implements SpuService {
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SpuDetailService spuDetailService;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SpuService spuService;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private SpecParamService paramService;
    @Autowired
    private SpuDetailService detailService;

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        Page<Spu> spuPage = new Page<>(page,rows);
        //准备查询条件
        this.page(spuPage,new QueryWrapper<Spu>()
                .eq(saleable!=null,"saleable",saleable)
                .eq(categoryId!=null,"categoryId",categoryId)
                .eq(brandId!=null,"brandId",brandId)
                .eq(id!=null,"id",id));
        //获取分页查出的集合
        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(spuPage.getRecords());
        for (SpuDTO spuDTO : spuDTOS) {
            //根据分类id的集合查询对应的分类集合 并且取出分类names 拼接为字符串
            String name = this.categoryService.listCategoryByIds(spuDTO.getCategoryIds()).stream()
                    .map(CategoryDTO::getName)
                    .collect(Collectors.joining("/"));
            spuDTO.setCategoryName(name);
            spuDTO.setBrandName(brandService.getById(spuDTO.getBrandId()).getName());

        }
        return new PageDTO<>(spuPage.getTotal(),spuPage.getPages(),spuDTOS);

    }

    @Transactional
    @Override
    public void saveGoods(SpuDTO spuDTO) {
        System.out.println(spuDTO.getSpuDetail()+"++++++");
        // 1.新增Spu

        Spu spu = spuDTO.toEntity(Spu.class);
        spu.setSaleable(false);
        boolean success = save(spu);//id回显
        if (!success) {
            throw new LyException(500, "新增商品失败");
        }
        // 2.新增SpuDetail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        System.out.println(spu.getId()+"++++++++++++++++");
        success = spuDetailService.save(spuDetail);
        if (!success) {
            throw new LyException(500, "新增商品详情失败");
        }
        // 3.新增Sku
//        List<Sku> list = spuDTO.getSkus().stream().map(skuDTO -> {
//            Sku sku = skuDTO.toEntity(Sku.class);
//            sku.setSaleable(false);
//            sku.setSpuId(spu.getId());
//            return sku;
//        }).collect(Collectors.toList());
        ArrayList<Sku> list = new ArrayList<>();

        List<SkuDTO> skus = spuDTO.getSkus();
        for (SkuDTO skuDTO : skus) {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSaleable(false);
            sku.setSpuId(spu.getId());
            list.add(sku);
        }
        // 批量新增
        skuService.saveBatch(list);
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
            // 根据品牌id查询品牌名称
            Brand brand = brandService.getById(spuDTO.getBrandId());
            if(brand != null) {
                spuDTO.setBrandName(brand.getName());
            }
        // 根据三级分类id查询分类集合
        List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
        if(!CollectionUtils.isEmpty(categories)) {
            // 取出分类的名称，拼接起来
            String names = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }
    }

    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        // 1.更新SPU
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        boolean success = updateById(spu);
        if (!success) {
            throw new LyException(500, "更新失败");
        }
        // 2.更新sku
        success =skuService.update().eq("spu_id", id).set("saleable", saleable).eq("spu_id",id).update();
        if (!success) {
            throw new LyException(500, "更新失败");
        }
        // 3.发送MQ消息
        String routingKey = saleable ? MQConstants.RoutingKeyConstants.ITEM_UP_KEY : MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME, routingKey, id);
    }

    @Override
    public SpuDTO queryGoodsById(Long spuId) {
        // 1.查询spu
        Spu spu = spuService.getById(spuId);
 //       Spu spu = getById(id);
        if (spu == null) {
            throw new LyException(400, "商品id不存在！");
        }
        // 1.2.转换DTO
        SpuDTO spuDTO = new SpuDTO(spu);

        // 2.查询spuDetail
        SpuDetail detail = spuDetailService.getById(spuId);
        if (detail == null) {
            throw new LyException(400, "商品id不存在！");
        }
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));

        // 3.查询sku
        List<Sku> list = skuService.query().eq("spu_id", spuId).list();
        if(CollectionUtils.isEmpty(list)){
            throw new LyException(400, "商品id不存在！");
        }
        spuDTO.setSkus(SkuDTO.convertEntityList(list));

        // 4.准备商品分类和品牌名称
        handleCategoryAndBrandName(spuDTO);

        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        // 1.修改spu
        // 1.1.判断是否存在spu的id，有说明需要修改，没有说明不需要
        Long spuId = spuDTO.getId();
        if(spuId != null){
            // 1.2.spu需要修改，更新spu, 转换dto
            Spu spu = spuDTO.toEntity(Spu.class);
            spu.setUpdateTime(new Date());
            // 1.3.更新
            boolean success = updateById(spu);
            if(!success){
                // 更新失败，抛出异常
                throw new LyException(500, "更新商品失败！");
            }
        }
        // 2.修改spuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        // 2.1.判断是否为null
        if (detailDTO != null && detailDTO.getSpuId() != null) {
            // 2.2.spuDetail存在，需要修改，转换DTO
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            boolean success = spuDetailService.updateById(detail);
            if(!success){
                // 更新失败，抛出异常
                throw new LyException(500, "更新商品失败！");
            }
        }
        // 3.修改sku
        List<SkuDTO> dtoList = spuDTO.getSkus();
        // 3.1.判断是否包含sku
        if(CollectionUtils.isEmpty(dtoList)){
            return;
        }
        List<Sku> skuList = dtoList.stream().map(skuDTO -> skuDTO.toEntity(Sku.class)).collect(Collectors.toList());

        // 3.2.转换DTO，并将sku根据saleable是否为null来分组。null，是新增或修改，不是null是删除
        Map<Boolean, List<Sku>> map = skuList.stream()
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));

        // 3.3.获取要新增或修改的sku
        List<Sku> insertOrUpdateList = map.get(true);
        // 如果不为空，则修改或新增
        if(!CollectionUtils.isEmpty(insertOrUpdateList)) {
            skuService.saveOrUpdateBatch(insertOrUpdateList);
        }

        // 3.4.获取要删除的sku
        List<Sku> deleteSkuList = map.get(false);
        if(!CollectionUtils.isEmpty(deleteSkuList)){
            // 存在要删除的sku
            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            // 删除
            skuService.removeByIds(idList);
        }
    }

    //根据Id查询商品Spu
    @Override
    public SpuDTO querySpuById(Long id) {
        return new SpuDTO(spuService.getById(id));
    }

    @Override
    public List<SpecParamDTO> listSpec(Long spuId, Boolean searching) {

        //spuId获取到对应的规格参数，以及规格参数值，规格参数组
        ;

        //查询spu获取分类id
        Long cid = getById(spuId).getCid3();

        //跟分类id查询当前分类下所有的规格参数组


        //普通，遍历规格参数组，根据每个组id查询对应的组内参数

        //跟分类id查询当前分类下所有的规格参数
        List<SpecParamDTO> specParamDTOS = SpecParamDTO
                .convertEntityList(this.paramService
                        .query()
                        .eq("category_id", cid)
                        .eq(null != searching, "searching", searching)
                        .list());

        //处理每一个specParam的value，？？在spuDetail中


        //对规格参数集合，进行分组，已groupId分组，同id，为一组,key为groupId，value同id一组集合


        //获取规格参数的value，
        SpuDetail spuDetail = this.detailService.getById(spuId);

        //json,class

        //nativeRead 第一个参数，接送，第二个参数，类型限定
        //key 规格参数的id，value，规格参数的值
        Map<Long, Object> valueMap = JsonUtils.nativeRead(spuDetail.getSpecification(), new TypeReference<Map<Long, Object>>() {
        });

        //遍历specParamDTO，给每个value赋值，每个value的值，就是valuemap的value
        specParamDTOS.forEach(specParamDTO -> {

            //规格参数的id
            Long key = specParamDTO.getId();

            specParamDTO.setValue(valueMap.get(key));
        });

        return specParamDTOS;
    }

    @Autowired
    private AmqpTemplate amqptemplate;


    @Override
    @Transactional
    public void modifySaleable(Long id, Boolean saleable) {

        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        spu.setUpdateTime(new Date());

        //update tb_spu set saleable = false ,update_time = now() where id = #{id}
        this.updateById(spu);

        Sku sku = new Sku();
        sku.setSaleable(saleable);
        sku.setUpdateTime(spu.getUpdateTime());

        //update tb_sku set saleable = false,update_time = now where spu_id = id
        //update的api中两个参数，新的sku，以及查询条件
        this.skuService.update(sku, new QueryWrapper<Sku>().eq("spu_id", id));

        //mq

        String routingKey = saleable ? "item.up" : "item.down";

        //向指定交换机发送消息，消息内容为spuId
        this.amqptemplate.convertAndSend("leyou.item", routingKey, id);
    }


}
